#include "ThreadCache.h"
#include "CentralCache.h"
void *ThreadCache::Allocate(size_t size)
{
    // 进行向上对齐
    assert(size <= MAX_BYTES);
    auto alignSize = SizeClass::RoundUp(size);
    size_t index = SizeClass::Index(size);
    if (!_freeLists[index].Empty())
    {
        return _freeLists[index].Pop();
    }
    else
    {
        return FetchFromCentralCache(index, alignSize);
    }
}

void ThreadCache::Deallocate(void *ptr, size_t size)
{
    assert(size <= MAX_BYTES && ptr);
    // 找出对应的映射的自由链表桶，对象插入
    size_t index = SizeClass::Index(size);
    _freeLists[index].Push(ptr);

    // tcmalloc 的结构更加的复杂，他考虑了连表的长度
    if (_freeLists[index].Size() >= _freeLists[index].MaxSize())
    {
        ListTooLong(_freeLists[index], size);;
    }
}
void ThreadCache::ListTooLong(FreeList& list, size_t size)
{
    void* start = nullptr, *end = nullptr;
    list.PopRange(start, end, list.MaxSize());
    CentralCache::GetInstance()->ReleaseListToSpans(start, size);
}
void *ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
    // 慢开始的调节算法
    // 如果你不要这个size的大小内存需求，那么batchNum 就会不断的增长，知道上限
    // the bigger the size is, the smaller the batchNum will be
    size_t batchNum = std::min(SizeClass::NumMoveSize(size), _freeLists[index].MaxSize());
    if (_freeLists[index].MaxSize() == batchNum)
    {
        _freeLists[index].MaxSize() += 1;
    }

    void* start = nullptr, *end = nullptr;
    size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);
    assert(actualNum >= 1);
    if (actualNum == 1)
    {
        assert(start == end);
        return start;
    }
    else
    {
        _freeLists[index].PushRange(NextObj(start), end, actualNum - 1);
        return start;
    }
    return nullptr;
}
